package edu.gxmzu.task.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import edu.gxmzu.task.config.security.MyUserDetails;
import edu.gxmzu.task.entity.Accounts;
import edu.gxmzu.task.entity.UserInfo;
import edu.gxmzu.task.entity.Works;
import edu.gxmzu.task.mapper.AccountsMapper;
import edu.gxmzu.task.mapper.UserInfoMapper;
import edu.gxmzu.task.mapper.WorksMapper;
import edu.gxmzu.task.models.UserModel;
import edu.gxmzu.task.service.AccountsService;
import edu.gxmzu.task.utils.JWTUtil;
import edu.gxmzu.task.utils.RedisService;
import edu.gxmzu.task.utils.Result;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

@Service
@Slf4j
public class AccountsServiceImpl implements AccountsService {
    @Resource
    private AccountsMapper accountsMapper;
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private RedisService redisService;
    @Autowired
    private WorksMapper worksMapper;

    private Accounts getUserByUsername(String username) {
        LambdaQueryWrapper<Accounts> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Accounts::getDeletionState, 0);
        wrapper.eq(Accounts::getUsername, username);
        return accountsMapper.selectOne(wrapper);
    }
    @Override
    public Result login(String username, String password) throws Exception {
        if (isNullOrEmpty(username)) return Result.badRequest("用户名/邮箱不能为空！");
        if (isNullOrEmpty(password)) return Result.badRequest("密码不能为空！");
        // 封装 authenticationToken
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        // authenticationManager 认证， 会调用loadUserByUsername
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if (Objects.isNull(authenticate)) throw new BadCredentialsException("用户名或密码错误！");
        // 获取UserDetails
        MyUserDetails myUserDetails = (MyUserDetails) authenticate.getPrincipal();
        Accounts accounts = myUserDetails.getAccount();
        // 封装数据并返回
        UserModel user = userInfoMapper.selectUserInfoById(accounts.getUserId());
        // 去除数据库中数据的校验
        user.setJwtToken(JWTUtil.createToken(user.getUserId(), username));
        // 存入redis
        redisService.setValue(RedisService.USER_KEY + username, myUserDetails);
        return Result.ok("登录成功！", user);
    }
    // 字符串是否为空或null
    public static boolean isNullOrEmpty(String value) {
        return value == null || value.trim().isEmpty();
    }

    // 字符串长度是否合法
    public static boolean isLengthValid(String value, int minLength, int maxLength) {
        return value.length() >= minLength && value.length() <= maxLength;
    }

    // 邮箱格式验证
    public static boolean isValidEmail(String email) {
        String regex = "^[a-zA-Z0-9]{3,18}@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$";
        return email.matches(regex);
    }
    @Override
    public Result register(String username, String password, String name, String email, Integer role) throws Exception {
        if (isNullOrEmpty(username))  return Result.badRequest("用户名不能为空！");
        if (!isLengthValid(username, 5, 20))  return Result.badRequest("用户名长度应在5-20字符！");
        if (isNullOrEmpty(password))  return Result.badRequest("密码不能为空！");
        if (!isLengthValid(password, 8, 20)) return Result.badRequest("密码长度应在8-20字符！");
        if (isNullOrEmpty(name))  return Result.badRequest("姓名不能为空！");
        if (!isLengthValid(name, 2, 20)) return Result.badRequest("姓名长度应在2-20字符！");
        if (isNullOrEmpty(email)) return Result.badRequest("邮箱不能为空！");
        if (!isValidEmail(email)) return Result.badRequest("邮箱格式有误！(主机部分3-18字符，且只能是0-9数字和大小写字母组成，-和多余的点都不行)");
        if (role == null) return Result.badRequest( "角色不能为空！");
        if (role != 0 && role != 1) return Result.badRequest("角色参数有误！(0普通用户(user)，1管理员(admin))");
        if (!Objects.isNull(getUserByUsername(username))) return Result.conflict("用户已存在！");
        Accounts user = new Accounts();
        user.setUsername(username);
        user.setEmail(email);
        user.setPassword(passwordEncoder.encode(password));
        int accountResult = accountsMapper.insert(user);
        if (accountResult != 1) return Result.fail("注册账号过程出现异常！");
        // 添加默认用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getUserId());
        userInfo.setName(name);
        if (role == 0) userInfo.setRoleId("0");
        else userInfo.setRoleId("1");
        userInfo.setCreateTime(System.currentTimeMillis() + "");
        int userInfoResult = userInfoMapper.insert(userInfo);
        if (userInfoResult != 1) return Result.fail("注册用户信息过程出现异常！");
        return login(username, password);
    }
    // 未登录不允许注销，因使用了Jwt拦截，只需校验token是否有效即可退出登录，无需传参再次校验
    @Override
    public Result logout() {
        // 无需删除SecurityContextHolder，因为每次请求都是新的
        // 此处的SecurityContextHolder已经由拦截器根据token自动更新
        UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Accounts accounts = (Accounts) authenticationToken.getPrincipal();
        // 删除缓存信息
        redisService.deleteValue(RedisService.USER_KEY + accounts.getUsername());
        return Result.ok("登出成功！");
    }
    @Override
    public Result deactivate(String userId) {
        Accounts accounts = accountsMapper.selectById(userId);
        if (Objects.isNull(accounts)) return Result.notFound("用户不存在！");
        accounts.setDeletionState(1);
        int result = accountsMapper.updateById(accounts);
        if (result != 1) return Result.fail("注销失败！");
        LambdaQueryWrapper<Works> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Works::getUserId, userId);
        List<Works> workLists = worksMapper.selectList(wrapper);
        for (Works work : workLists){
            work.setDeletionState(1);
            int workResult = worksMapper.updateById(work);
            if (workResult != 1) return Result.fail("删除对应任务失败！");
        }
        // 删除缓存信息
        redisService.deleteValue(RedisService.USER_KEY + accounts.getUsername());
        redisService.deleteValue(RedisService.USER_KEY + accounts.getEmail());
        return Result.ok("注销成功！");
    }
}
